题目
给你一个字符串 s 和一个字符串数组 dictionary 作为字典,找出并返回字典中最长的字符串,该字符串可以通过删除 s 中的某些字符得到。
如果答案不止一个,返回长度最长且字典序最小的字符串。如果答案不存在,则返回空字符串。
示例 1:
1 2
   | 输入:s = "abpcplea", dictionary = ["ale","apple","monkey","plea"] 输出:"apple"
   | 
 
示例 2:
1 2
   | 输入:s = "abpcplea", dictionary = ["a","b","c"] 输出:"a"
   | 
 
提示:
- 1 <= s.length <= 1000
 
- 1 <= dictionary.length <= 1000
 
- 1 <= dictionary[i].length <= 1000
 
- s 和 dictionary[i] 仅由小写英文字母组成
 
方法一:排序+双指针
比较直接简单的思路,就是利用自定义sort函数,满足最长、字典序最小的要求,再用双指针遍历每一个单词,得到的第一个解就是该题目的解。
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
   | class Solution { public:     string findLongestWord(string s, vector<string>& dictionary) {         int n = dictionary.size();                  sort(dictionary.begin(),dictionary.end(),[&](string s1,string s2){             if(s1.size()!=s2.size()){                 return s1.size()>s2.size();             }else{                 return s1<s2;             }         });         string ans;                  for(auto & word : dictionary){             int i=0,j=0;                          while(i<s.size() && j<word.size()){                 if(word[j]==s[i]){                     i++;                     j++;                 }else{                     i++;                 }             }                          if(j==word.size()){                 ans = word;                 break;             }         }         return ans;     } };
  | 
 
方法二: 双指针+维护最优解
一个贪心思路:当s中存在两个相同字符和词典中的单词匹配时,优先选择匹配靠前的字符。
该方法较方法一时间复杂度高
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
   | class Solution { public:     string findLongestWord(string s, vector<string>& dictionary) {         int n = dictionary.size();                  string ans;                  for(auto & word : dictionary){             int i=0,j=0;                          while(i<s.size() && j<word.size()){                 if(word[j]==s[i]){                     i++;                     j++;                 }else{                     i++;                 }             }                                       if(j==word.size()){                 if(word.size()>ans.size() || (word.size()==ans.size()&& word<ans))                     ans = word;             }         }         return ans;     } };
  | 
 
方法三:动态规划
针对方法2进行改进,使用DP数组,对双指针遍历部分进行简化。
DP数组虽然是二维,但是一层的长度只要涵盖26个英文字母就好。状态转移方程为:
其含义是,对于s中的第$i$个位置,字符j将会在$dp[i][j]$处出现,所以显然当$s[i]=j$时,出现为$i$,否则就看看$i+1$是否知道位置。
因此该DP数组要倒退实现。
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
   | class Solution { public:     string findLongestWord(string s, vector<string>& dictionary) {         int n = s.size();         vector<vector<int>> dp(n+1,vector<int>(26,n));                           for(int i=n-1;i>=0;i--){             for(int j=0;j<26;j++){                 if('a'+j==s[i]){                     dp[i][j]=i;                 }else{                     dp[i][j] = dp[i+1][j];                 }                              }                      }         string ans="";                  for(auto & word : dictionary){             bool match=true;             int i=0;             for(auto & c : word){                 if(dp[i][c-'a']==n){                     match=false;                     break;                 }else{                     i = dp[i][c-'a']+1;                 }             }
                                        if(match){                 if(word.size()>ans.size() || (word.size()==ans.size()&& word<ans))                     ans = word;             }         }         return ans;     } };
  | 
 
        
            
        
        
          
              原文链接: https://zijian.wang/2021/09/13/524. 通过删除字母匹配到字典里最长单词(排序 双指针 二维DP)/
              版权声明: 转载请注明出处.